home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / tex / uniq.zip / UNIQ.C < prev    next >
C/C++ Source or Header  |  1994-05-23  |  5KB  |  224 lines

  1. /* UNIX uniq text utility for MS-DOS
  2.  *
  3.  * uniq -  remove or report adjacent duplicate lines
  4.  *
  5.  * Usage: uniq [ -cdu ] [ +|-n ] [ inputfile [ outputfile ] ]
  6.  *
  7.  * uniq version 1.1, 23-May-94 by Jason Mathews
  8.  *
  9.  * Copyright (C) 1992-94 by Jason Mathews.  Permission is granted to any
  10.  * individual or institution to use, copy or redistribute this software so long
  11.  * as it is not sold for profit, provided this copyright notice is retained.
  12.  *
  13.  * Modification history:
  14.  *
  15.  *   V1.0 23-Nov-92 Original version (clone of the UNIX uniq command)
  16.  *                  Compiled and tested with Borland C++ V3.1 compiler.
  17.  *   V1.1 23-May-94 Fixed skip field/character processing.
  18.  ****************************************************************************/
  19.  
  20. #include <stdio.h>
  21. #include <stdlib.h>
  22. #include <string.h>
  23.  
  24. #define MAX_STRING_LEN 1024
  25. #define whitespace(c) ((c)==' ' || (c)=='\t')
  26.  
  27. /* define alternate switch for non-unix systems */
  28. #ifdef unix
  29. #  define ALT_SW
  30. #else
  31. #  define ALT_SW **argv=='/' ||
  32. #endif
  33.  
  34. typedef unsigned char Bool;
  35. typedef unsigned char UChar;
  36. typedef char String[MAX_STRING_LEN];
  37.  
  38. enum { DEFAULT=0, DUPS, COUNT_LINES, NOREPEATS };
  39.  
  40. /* input buffer for the current and previous input lines */
  41. String    buffer[2] = { "", "" };
  42.  
  43. int    numFields = 0;
  44. int    indent = 0;
  45. Bool    newbuf = 0; /* buffer index toggles between 1 and 0 */
  46. Bool    showCount = 0;
  47. int    count = 0;
  48. UChar    mode = DEFAULT;
  49.  
  50. /* Function prototypes */
  51.  
  52. char*    fgetline(char *s, int n, FILE *fp);
  53. void    CheckState(char *s);
  54. int    CheckLine(void);
  55.  
  56. int main (int argc, char **argv)
  57. {
  58.     Bool gotFirstLine = 0; /* flag indicating we have stored the first line */
  59.     char *filename;
  60.  
  61.     /* skip over 0 argument and increment through arg-list */
  62.     while (*(++argv))
  63.     {
  64.     if (ALT_SW **argv == '-')
  65.     {
  66.      switch (*(++*argv)) {
  67.      case 'd': /* write one copy of repeated lines */
  68.         mode = DUPS;
  69.         break;
  70.      case 'c': /* Precede each line with a count of the number of times it occured */
  71.         mode = COUNT_LINES;
  72.         break;
  73.      case 'u': /* copy only lines not repeated in the orginal file */
  74.         mode = NOREPEATS;
  75.         break;
  76.      case 'h':
  77.      case '?':
  78.         fprintf(stderr,
  79.           "uniq (C) 1992-94 Jason Mathews\n\n"
  80.           "Usage: uniq [ -cdu ] [ +|-n ] [ inputfile [ outputfile ] ]\n"
  81.           "  -c  Precede each line with a count of the number of times it occurred\n"
  82.           "  -d  Write one copy of duplicate lines\n"
  83.           "  -u  Copy only lines not repeated in the orginal file\n"
  84.           "  +n  Skips over the first n characters\n"
  85.           "  -n  Skips over the first n fields\n");
  86.         return 0;
  87.      default:
  88.         if (*(*argv-1) != '/')
  89.         {
  90.             numFields = atoi(*argv);
  91.             if (numFields < 0) numFields = 0;
  92.         }
  93.       } /* switch */
  94.     }
  95.     else if (**argv == '+')
  96.     {
  97.         indent = atoi(*argv+1);
  98.         if (indent < 0) indent = 0;
  99.     }
  100.     else break;
  101.     } /* while */
  102.  
  103.     if (*argv != NULL)
  104.     {
  105.     filename = *argv++;
  106.     /* redirect stdin to file */
  107.     if (freopen (filename, "r", stdin) == 0)
  108.     {
  109.         fprintf(stderr, "uniq: cannot open %s\n", filename);
  110.         return 1;
  111.     }
  112.     }
  113.  
  114.     if (*argv != NULL)
  115.     {
  116.     filename = *argv++;
  117.     /* redirect stdout to file */
  118.     if (freopen( filename, "w", stdout ) == 0)
  119.     {
  120.         fprintf(stderr, "uniq: cannot create %s\n", filename);
  121.         return 1;
  122.     }
  123.     }
  124.  
  125.     while (fgetline(buffer[newbuf], MAX_STRING_LEN, stdin))
  126.       {
  127.     if (gotFirstLine != 0) /* do we have two lines to compare? */
  128.       {
  129.         if (CheckLine()) count++; /* if duplicate */
  130.         else
  131.           {
  132.         CheckState( buffer[newbuf] );
  133.         count = 1; /* reset counter */
  134.           }
  135.       }
  136.     else
  137.       {
  138.         gotFirstLine = 1;
  139.         count = 1;
  140.         newbuf = !newbuf; /* toggle buffer to next location */
  141.       }
  142.       } /* while */
  143.  
  144.     /* check last input line */
  145.     if (gotFirstLine)
  146.       {
  147.     CheckState( buffer[!newbuf] );
  148.       }
  149.     return 0;
  150. } /* end main */
  151.  
  152. /*
  153.  *  fgetline - get line from file
  154.  */
  155. char* fgetline (char *s, int n, FILE *fp)
  156. {
  157.   register    int    c;
  158.   register    char   *P = s;
  159.  
  160.   /* read until the end of line or the end of file is reached */
  161.   while (((c = getc(fp)) != '\n') && c != EOF)
  162.     {
  163.       if (--n > 0) *P++ = c;
  164.     }
  165.   if (EOF == c && P == s)  return( NULL );
  166.   *P = 0;
  167.   return (ferror (fp)) ? NULL : s;
  168. }
  169.  
  170. /*
  171.  *  Adjust - adjust line for specified fields/characters
  172.  */
  173. char* Adjust( char *s )
  174. {
  175.     int count = 0;
  176.     /* ignore first n fields */
  177.     while (*s && count++ < numFields)
  178.     {
  179.     while (whitespace(*s)) s++;
  180.     while (*s && !whitespace(*s)) s++;
  181.     }
  182.  
  183.     count = indent;
  184.     /* ignore first n characters */
  185.     while (count != 0 && *s != 0)
  186.     {
  187.     s++;
  188.     count--;
  189.     }
  190.  
  191.     return s;
  192. }
  193.  
  194. /*
  195.  *  CheckLine - check and parse current input line
  196.  *
  197.  *  Returns: 1 if line matches previous line, 0 otherwise.
  198.  */
  199. int CheckLine ()
  200. {
  201.     char *s1 = Adjust(buffer[newbuf]);
  202.     char *s2 = Adjust(buffer[!newbuf]);
  203.  
  204.     /* duplicate string? */
  205.     if (!strcmp(s1, s2)) return 1;
  206.  
  207.     newbuf = !newbuf; /* toggle buffer to next location */
  208.     return 0;       /* unique line */
  209. } /* end CheckLine */
  210.  
  211. /*
  212.  *  CheckState - print line if appropriate to selected mode
  213.  */
  214. void CheckState (char *s)
  215. {
  216.     if (mode == COUNT_LINES) printf("%4d %s\n", count, s);
  217.     else
  218.     {
  219.     if (mode==DEFAULT || mode==NOREPEATS && count==1 ||
  220.         mode==DUPS && count > 1)
  221.         printf("%s\n", s);
  222.     }
  223. }
  224.